#include "CDGWidget.h"

#include <sys/types.h> 
#include <sys/wait.h> 
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <mythtv/lcddevice.h>

#include <qdir.h>
#include <qfile.h>
#include <qimage.h>
#include "constants.h"
#include "decoder.h"

CDGWidget::CDGWidget(QWidget *parent, const char *name )
    : QWidget( parent, name ),
      m_pixsize(1),
      m_border_top(0),
      m_border_left(0)
{
    hide();
    this->setGeometry(0, 0, parent->width(), parent->height());
}

CDGWidget::~CDGWidget()
{
    cerr << "exit" << endl;
    stop();
}

void CDGWidget::stop()
{
    if (m_timer)
    {
        m_timer->stop();
        delete m_timer;
        m_timer = 0;
    }

    stopDecoder();

    if (m_output)
    {
        delete m_output;
        m_output = 0;
    }
    
    if(m_input)
    {
        delete m_input;
        m_input = 0;
    }

    hide();

    //LCD
    LCD *lcd = LCD::Get();
    if (lcd)
       lcd->switchToTime();

    m_isactive = false;

}

bool CDGWidget::play(const QString& filename, bool useTransp, bool useTransBkg, bool useTransBorder)
{
    //Setup
    m_parsed = 0;
    m_isplaying = false;
    m_isactive = false;

    //Open CDG file
    if(!m_cdg.start(std::string(filename.latin1()),useTransp,useTransBkg,useTransBorder))
       return false;

    //Save info
    m_cdgFile = filename;

    //Open MP3 file
    QString mp3file = filename.left(filename.findRev('.'));
    QFile test(mp3file+".mp3");
    if (test.exists())
       mp3file += ".mp3";
    else
       mp3file += ".MP3";
    m_input = new QFile(mp3file);

    //CDG animations size (removing border)
    m_pixsize = (this->width()/300);
    if((this->height()/216)<m_pixsize)
       m_pixsize = (this->height()/216);

    m_border_left = (this->width()-(m_pixsize*300))/2;
    m_border_top = (this->height()-(m_pixsize*216))/2;

    // Make transparent mask by default
    m_mask.resize(this->size());
    m_mask.fill(Qt::color0);

    // Setup offscreen image
    m_offscreen.resize(this->size());
    m_offscreen.fill(Qt::black);
    m_offscreen.setMask(m_mask);

    //Background
    printf("Loading backgroundimage\n");
    QString setting = gContext->GetSetting("CdgBackgroundPath");
    cerr << "Bkg: Backgroundpath: " << setting << endl;
    m_bgimage.resize(this->size());
    m_bgimage.fill(Qt::black);

    QImage background;
    QDir imageDir(setting);
    if (imageDir.isReadable())
    {
        //Find all backgrounds
        const QFileInfoList* List = imageDir.entryInfoList();
        QFileInfoList result;
        QString image;
        for (QFileInfoListIterator it(*List); it; ++it)
        {   
            QFileInfo* file = it.current();
            QString filename = file->fileName();
            
            if (filename == "." || filename == "..")
            {   
                continue;
            }
            if (!file->isDir() && ((file->extension(false) == "jpg") ))
            {
               result.append(file);
            }
        }

        //Use one of the found background
        srand((unsigned)time(0)); 
        if(result.count() > 0)
        { 
            int imagepos = rand()%result.count(); 
            cerr << "Got " << imagepos << " of " << result.count() << endl;
            if(!background.load(image))
               printf("Loading image FAILED\n");
            QImage scaled = background.smoothScale(this->size());
            m_bgimage.convertFromImage(scaled);
            
        }
    }


    if (!m_output)
        openOutputDevice(this);
   
    if (m_decoder && !m_decoder->factory()->supports(mp3file))
        m_decoder = 0;

    if (!m_decoder) 
    {
        printf("Support? %s\n",mp3file.data());
        m_decoder = Decoder::create(mp3file, m_input, m_output);

        if (!m_decoder) 
        {
            printf("decoder: unsupported fileformat\n");
//            stopAll();
            return false;
        }

        m_decoder->setBlockSize(globalBlockSize);
        m_decoder->addListener(this);
    } 
    else 
    {
        m_decoder->setInput(m_input);
        m_decoder->setFilename(mp3file);
        m_decoder->setOutput(m_output);
    }

    if (m_decoder->initialize()) 
    {
        if (m_output)
        {
            m_output->Reset();
        }

        printf("decoder start\n");
        m_decoder->start();
    }

    //Create timer if needed and start animation
    if(!m_timer) {
        m_timer = new QTimer( this );
        connect( m_timer, SIGNAL(timeout()), this, SLOT(nextPos()) );
    }
    m_timer->start(animTimer);

    show();    
    m_isplaying = !m_isplaying;
    m_isactive = true;
    return true;
}


void CDGWidget::nextPos()
{
    int msec = m_output->GetAudiotime();

    // Read 3 pkgs each 10ms
    int read = ((msec*3)/10)-m_parsed;
    
    //Only FFWD right now...
    if(read<0) return;

    m_cdg.handlePackets(read);
    m_parsed += read;
    
    CDG_Area_t area;
    m_cdg.getUpdateArea(area);

    if((-1==area.tl_x)||(-1==area.tl_y)||(-1==area.br_x)||(-1==area.br_y))
       return;

    // Repaint 1 pixel outside to get frame correctly
    if(area.tl_x>0) area.tl_x -= 1;
    if(area.tl_y>0) area.tl_y -= 1;
    if(area.br_x<299) area.br_x += 1;
    if(area.br_y<215) area.br_y += 1;

    //Create CDG
    m_cdg.generateImage();

//     //Create frame
//     if(m_showFrame)
//        m_cdg.generateFrame();

    setUpdatesEnabled(false);

    QPainter p;
    QPainter m;
    p.begin( &m_offscreen );

    m.begin( &m_mask );
    m.setPen(QPen(color1));
    m.setBrush(color1);
    for(int x=area.tl_x; x<area.br_x; ++x)
    {
        for(int y=area.tl_y; y<area.br_y; ++y)
        {
            QColor c(m_cdg.image[y][x][0],
                     m_cdg.image[y][x][1],
                     m_cdg.image[y][x][2]);
            p.setPen(QPen(c));
            p.setBrush(c);
            
            if(m_cdg.image[y][x][3] == 0) //If transparent
            {
                // Paint the frame Up, Down ..
                m.setPen(QPen(color0));
                m.setBrush(color0);
                m.drawRect(m_border_left+(x*m_pixsize), m_border_top+(y*m_pixsize),m_pixsize,m_pixsize);
                m.setPen(QPen(color1));
                m.setBrush(color1);

                //Up
                if((y>0)&&(y<216))
                {
                    if(!(m_cdg.image[y-1][x][3] == 0))
                   {
                       p.drawRect(m_border_left+(x*m_pixsize), m_border_top+(y*m_pixsize),m_pixsize,1);
                       m.drawRect(m_border_left+(x*m_pixsize), m_border_top+(y*m_pixsize),m_pixsize,1);
                   }
                }
                //Down
                if((y>=0)&&(y<215))
                {
                   if(!(m_cdg.image[y+1][x][3] == 0))
                   {
                       p.drawRect(m_border_left+(x*m_pixsize), m_border_top+(y*m_pixsize)+(m_pixsize-1),m_pixsize,1);
                       m.drawRect(m_border_left+(x*m_pixsize), m_border_top+(y*m_pixsize)+(m_pixsize-1),m_pixsize,1);
                   }
                }
                //Left
                if((x>0)&&(x<300))
                {
                    if(!(m_cdg.image[y][x-1][3] == 0))
                   {
                       p.drawRect(m_border_left+(x*m_pixsize), m_border_top+(y*m_pixsize),1,m_pixsize);
                       m.drawRect(m_border_left+(x*m_pixsize), m_border_top+(y*m_pixsize),1,m_pixsize);
                   }
                }
                //Right
                if((x>=0)&&(x<299))
                {
                    if(!(m_cdg.image[y][x+1][3] == 0))
                   {
                       p.drawRect(m_border_left+(x*m_pixsize)+(m_pixsize-1), m_border_top+(y*m_pixsize),1,m_pixsize);
                       m.drawRect(m_border_left+(x*m_pixsize)+(m_pixsize-1), m_border_top+(y*m_pixsize),1,m_pixsize);
                   }
                }
            }
            else 
            {
                // Just paint the pixel
                p.drawRect(m_border_left+(x*m_pixsize), m_border_top+(y*m_pixsize),m_pixsize,m_pixsize);
                m.drawRect(m_border_left+(x*m_pixsize), m_border_top+(y*m_pixsize),m_pixsize,m_pixsize);
            }
        }
    }
    p.end();
    m.end();
    m_offscreen.setMask(m_mask);

    setUpdatesEnabled(true);
    repaint(QRect( m_border_left+(area.tl_x*m_pixsize), m_border_top+(area.tl_y*m_pixsize), 
                   (area.br_x-area.tl_x)*m_pixsize, (area.br_y-area.tl_y)*m_pixsize),
            false);
}

void CDGWidget::paintEvent(QPaintEvent * e)
{
//    printf("Update %d %d %d %d \n",e->rect().left(),e->rect().right(),
//           e->rect().top(),e->rect().bottom());
    QPixmap newscreen(e->rect().width(), e->rect().height());
    bitBlt(&newscreen, 0, 0, &m_bgimage  , e->rect().left(), e->rect().top(),
           e->rect().width(), e->rect().height());
    bitBlt(&newscreen, 0, 0, &m_offscreen, e->rect().left(), e->rect().top(),
           e->rect().width(), e->rect().height());

    bitBlt(this, e->rect().left(), e->rect().top(), &newscreen);
}

void CDGWidget::info()
{
     QString info = "CDG:\n"+m_cdgFile+"\n\nMp3";
     cerr << "INFO: " << info << endl;
//     m_info.show(info);
}

void CDGWidget::customEvent(QCustomEvent *event)
{
    switch ((int)event->type()) 
    {
        case OutputEvent::Playing:
        {
            printf("Playing stream.\n");
            break;
        }

        case OutputEvent::Buffering:
        {
            printf("Stream buffering.\n");
            break;
        }

        case OutputEvent::Paused:
        {
            printf("Stream paused.\n");
            break;
        }

        case OutputEvent::Info:
        {
            OutputEvent *oe = (OutputEvent *) event;

            int eh, em, es, rs, ts;
            rs = ts = oe->elapsedSeconds();

            eh = ts / 3600;
            em = (ts / 60) % 60;
            es = ts % 60;

            QString time_string;
            
            if (eh > 0) 
               time_string.sprintf("%d:%02d:%02d", eh, em, es);
            else 
               time_string.sprintf("%02d:%02d", em, es);                   
            
            printf("%s\n",time_string.data());
            break;
        }
        case OutputEvent::Error:
        {
            printf("Output error.\n");
            break;
        }
        case DecoderEvent::Stopped:
        {
            printf("Stream stopped.\n");
            break;
        }
        case DecoderEvent::Finished:
        {
            printf("Finished playing stream.\n");
            printf("Lets exit.\n");
            stop();
            break;
        }
        case DecoderEvent::Error:
        {
            printf("Decoder error.\n");
            break;
        }
    }

    QWidget::customEvent(event);
}
